<?php

namespace app\beautiful\controller\miniapp\member;

use app\BaseController;

use app\beautiful\logic\printer\PrinterLogic;

use app\beautiful\model\appointment\AppointmentModel;

use app\beautiful\model\appointment\AppointmentSettingModel;

use app\beautiful\model\appointment\TechnicianModel;

use app\beautiful\model\appointment\TechnicianProjectModel;

use app\beautiful\model\appointment\TechnicianSchedulingModel;

use app\beautiful\model\member\MemberProjectModel;

use app\beautiful\model\project\ProjectModel;

use app\beautiful\model\project\ProjectTypeModel;

use app\beautiful\model\setting\SettingSmsModel;

use app\common\logic\SmsLogic;



class Appointment extends BaseController{



    protected $setting;

    protected function initialize()

    {

        parent::initialize(); // TODO: Change the autogenerated stub

        if(null === $setting= AppointmentSettingModel::where([['shop_id','=',$this->request->shopId]])->find()){

            $this->error('您还未设置预约')->send();

            die();

        }

        $this->setting=$setting;



        if(!in_array(date('w',$this->request->time()),$this->setting->week)){

            $this->error($this->setting->rest_notice)->send();

            die();

        }



    }



    public function showAppointment()

    {

        $technician_data=$this->getTechnicianData();

        $project_type_data=$this->getProjectTypeData();

        $project_data=$this->getProjectData();



        $return=[

            'technician_data'=>$technician_data,

            'project_type_data'=>$project_type_data,

            'project_data'=>$project_data,

        ];

        return $this->success($return);

    }



    public function getTechnicianDetail()

    {

        $technician_id=$this->request->param('technician_id/d',0);

        if($technician_id==0) return $this->error('技师不存在');

        if(null === $technician = TechnicianModel::find($technician_id)) return $this->error('技师不存在');

        if($technician->shop_id != $this->request->shopId) return $this->error('技师不存在');

        if($technician->is_delete != 0) return $this->error('技师不存在');

        $engaged_num=TechnicianProjectModel::where([

            ['shop_id','=',$this->request->shopId],

            ['technician_id','=',$technician_id],

            ['is_delete','=',0]

        ])->sum('engaged_num') ?? 0;



        $project_data=TechnicianProjectModel::with(['project'=>function($query){

            $query->where([['is_delete','=',0]])

                ->field('project_id,abbreviation,market_price,cover_img');

        }])->where([

                ['shop_id','=',$this->request->shopId],

                ['technician_id','=',$technician_id],

                ['is_delete','=',0]

            ])->order(['engaged_num'=>'desc'])

            ->field('project_id,engaged_num')

            ->select()

            ->toArray();

        foreach ($project_data as $k => $v){

            if(!$v['project']){

                unset($project_data[$k]);

            }

        }



        $detail=[

            'face'=>$technician->face,

            'name'=>$technician->name,

            'working_collar'=>$technician->working_collar,

            'position'=>$technician->position,

            'engaged_num'=>$engaged_num,

            'brief_introduction'=>$technician->brief_introduction,

            'tags'=>$technician->tags ?? [],

            'project_data'=>$project_data,

        ];



        return $this->success(['detail'=>$detail]);

    }



    public function showAppointmentApply()

    {

        $project_id = $this->request->param('project_id/d',0);



        if(null === $project = ProjectModel::find($project_id)) return $this->error('服务项目不存在');

        if($project->shop_id != $this->request->shopId) return $this->error('服务项目不存在');

        if($project->is_delete != 0) return $this->error('服务项目不存在');

        $engaged_num=TechnicianProjectModel::where([

            ['shop_id','=',$this->request->shopId],

            ['project_id','=',$project_id]

        ])->sum('engaged_num') ?? 0;



        $project_detail=[

            'project_id'=>$project->project_id,

            'abbreviation'=>$project->abbreviation,

            'market_price'=>$project->market_price,

            'cover_img'=>$project->cover_img,

            'engaged_num'=>$engaged_num,

        ];



        $technician_ids=TechnicianProjectModel::where([

                ['shop_id','=',$this->request->shopId],

                ['project_id','=',$project_id],

                ['is_delete','=',0]

            ])->column('technician_id') ?? [];



        $technician_data=$this->getTechnicianData($technician_ids);



        $return=[

            'project_detail'=>$project_detail,

            'technician_data'=>$technician_data,

            'week'=>$this->setting->week,

        ];

        return $this->success($return);

    }



    public function getAppointmentApplyTime()

    {

        $today=date("Y-m-d",$this->request->time());

        $project_id = $this->request->param('project_id/d',0);



        $day=$this->request->param('day');

        if(empty($day)) return $this->error('请选择预约日期');

        if(false === $day_unix=strtotime($day.' 00.00.00')) return $this->error('请选择预约日期');

        if(!in_array(date('w',$day_unix),$this->setting->week)) return $this->error('选的日期不能进行预约');

        if($day<$today) return $this->error('预约日期不能低于今天');



        if(null === $project = ProjectModel::find($project_id)) return $this->error('服务项目不存在');

        if($project->shop_id != $this->request->shopId) return $this->error('服务项目不存在');

        if($project->is_delete != 0) return $this->error('服务项目不存在');



        $technician_id=$this->request->param('technician_id/d',0);

        if($technician_id != 0){

            if(null === $technician = TechnicianModel::find($technician_id)) return $this->error('技师不存在');

            if($technician->shop_id != $this->request->shopId) return $this->error('技师不存在');

            if($technician->is_delete != 0) return $this->error('技师不存在');



            $time_list=$this->getTechnicianAppointmentTime($day,$project_id,$technician_id);
        }else{

            $time_list=$this->getAppointmentTime($day);

        }



        return $this->success(['time_list'=>$time_list]);



    }



    public function saveAppointment()

    {

        $today=date("Y-m-d",$this->request->time());

        $project_id = $this->request->param('project_id/d',0);

        $technician_id=$this->request->param('technician_id/d',0);

        $scheduling_id=$this->request->param('scheduling_id/d',0);

        $start_time=$this->request->param('start_time');

        $end_time=$this->request->param('end_time');



        //判断传来的参数

        $day=$this->request->param('day');

        if(empty($day)) return $this->error('请选择预约日期');

        if(false === $day_unix=strtotime($day.' 00.00.00')) return $this->error('请选择预约日期');

        if(!in_array(date('w',$day_unix),$this->setting->week)) return $this->error('选的日期不能进行预约');

        if($day<$today) return $this->error('预约日期不能低于今天');

        if(false === $start_time_unix=strtotime($day.' '.$start_time.':00')) return $this->error('请选择预约开始时间');

        if($start_time_unix<=$this->request->time()) return $this->error('预约开始时间低于当前时间');

        if(false === $end_time_unix=strtotime($day.' '.$end_time.':00')) return $this->error('请选择预约结束时间');

        $interval=$end_time_unix-$start_time_unix;

        if($interval<=0) return $this->error('预约开始时间不能大于结束时间');

        if($interval%1800!=0)return $this->error('预约时间间隔必须是30分钟的整倍');

        if($day.' '.$start_time<date("Y-m-d H:i",($this->request->time()+(3600*$this->setting->appointment_advance)))) return $this->error('预约时间已过');



        //判断项目

        if(null === $project = ProjectModel::find($project_id)) return $this->error('服务项目不存在');

        if($project->shop_id != $this->request->shopId) return $this->error('服务项目不存在');

        if($project->is_delete != 0) return $this->error('服务项目不存在');



        //判断是否拥有项目

        if($this->setting->check_member_project==1){

            if(null === MemberProjectModel::where([

                    ['shop_id','=',$this->request->shopId],

                    ['member_id','=',$this->request->memberId],

                    ['project_id','=',$project_id],

                    ['remain_num','>',0],

                    ['valid_end_time','>=',date("Y-m-d",$this->request->time())]

                ])->find()){

                return $this->error('您没有这个项目,无法预约');

            }

        }



        //判断一个项目只有预约一次

        if(null !== AppointmentModel::where([

                ['shop_id','=',$this->request->shopId],

                ['status','in',[1,4,8]],

                ['day','=',$day],

                ['member_id','=',$this->request->memberId]

            ])->find()){

            return $this->error('这个项目您今天已经预约过了');

        }



        if($technician_id != 0){

            //有技师的情况

            //判断技师

            if(null === $technician = TechnicianModel::find($technician_id)) return $this->error('技师不存在');

            if($technician->shop_id != $this->request->shopId) return $this->error('技师不存在');

            if($technician->is_delete != 0) return $this->error('技师不存在');



            //判断技师的排班

            if($scheduling_id==0) return $this->error('请选择时间');

            if(null === $scheduling = TechnicianSchedulingModel::find($scheduling_id)) return $this->error('请选择时间');

            if($scheduling->shop_id != $this->request->shopId) return $this->error('请选择时间');

            if($scheduling->is_delete != 0) return $this->error('请选择时间');

            if($scheduling->technician_id != $technician_id) return $this->error('请选择时间');

            if($scheduling->day != $day) return $this->error('请选择时间');

            if($scheduling->project_id != $project_id) return $this->error('请选择时间');



            //判断技师排班的数量有没有超过

            $scheduling_num=AppointmentModel::where([

                ['shop_id','=',$this->request->shopId],

                ['scheduling_id','=',$scheduling_id],

                ['status','in',[1,4,8]]

            ])->count() ?? 0;



            $appointment_num=$scheduling->appointment_num ==0 ? $this->setting->appointment_num : $scheduling->appointment_num;

            if($scheduling_num>=$appointment_num) return $this->error('该时间段预约已经满了，请重新选择');

        }else{

            //没有技师的情况

            //判断时间段的预约数

            $appointment_num = AppointmentModel::where([

                ['shop_id','=',$this->request->shopId],

                ['status','in',[1,4,8]],

                ['day','=',$day],

            ])->whereRaw("(start_time <= '{$start_time}' and end_time >= '{$start_time}') or (start_time <= '{$end_time}' and end_time >= '{$end_time}')")

                ->count() ?? 0;



            if($appointment_num>=$this->setting->appointment_num) return $this->error('该时间段预约已经满了，请重新选择');

        }



        $appointment_model=new AppointmentModel();

        $appointment_model->shop_id=$this->request->shopId;

        $appointment_model->member_id=$this->request->memberId;

        $appointment_model->member_name=$this->request->member->nick_name;

        $appointment_model->member_mobile=$this->request->member->mobile;

        $appointment_model->project_id=$project_id;

        $appointment_model->project_name=$project->abbreviation;

        $appointment_model->project_cover_img=$project->cover_img;

        $appointment_model->technician_id=$technician_id;

        if($technician_id!=0){

            $appointment_model->scheduling_id=$scheduling_id;

            $appointment_model->technician_name=$technician->name;

            $appointment_model->technician_mobile=$technician->mobile;

        }



        $appointment_model->day=$day;

        $appointment_model->start_time=$start_time;

        $appointment_model->end_time=$end_time;

        $appointment_model->save();



        try{

            //发送短信给用户

            $sms_setting = SettingSmsModel::where([['shop_id','=',$this->request->shopId]])->find();

            if(null !== $sms_setting){

                if($sms_setting->appointment_notice_member==1){

                    $sms_logic= new SmsLogic();

                    $params=[

                        'xm'=>$project->abbreviation,

                        't'=>$start_time.'-'.$end_time

                    ];

                    $sms_logic->send($this->request->shopId,[$this->request->member->mobile],$params,'appointmentNoticeMember');

                }



                //发送短信给服务人员

                if($technician_id !=0 ){

                    if($sms_setting->appointment_notice_service_person==1){

                        $sms_logic= new SmsLogic();

                        $params=[

                            'mobile'=>$this->request->member->mobile,

                            'xm'=>$project->abbreviation,

                            't'=>$start_time.'-'.$end_time

                        ];

                        $sms_logic->send($this->request->shopId,[$technician->mobile],$params,'appointmentNoticeServicePerson');

                    }

                }



                //发送给管理员

                if($sms_setting->appointment_notice_admin==1 && !empty($sms_setting->boss_mobiles)){

                    $sms_logic= new SmsLogic();

                    $params=[

                        'mobile'=>$this->request->member->mobile,

                        'xm'=>$project->abbreviation,

                        't'=>$start_time.'-'.$end_time

                    ];

                    $sms_logic->send($this->request->shopId,$sms_setting->boss_mobiles,$params,'appointmentNoticeAdmin');

                }

            }





        }catch (\Exception $e){



        }



        //打印机

        $printer_logic =new PrinterLogic($this->request->shopId);

        $printer_logic->print('appointment',$appointment_model->appointment_id);

        return $this->success('操作成功');

    }



    public function getMemberAppoinment()

    {

        $type=$this->request->param('type/d',0);

        $where=[

            ['shop_id','=',$this->request->shopId],

            ['member_id','=',$this->request->memberId],

        ];

        switch ($type){

            case 1:

                $where[]=['status','=',4];

                break;

            case 2:

                $where[]=['status','=',8];

                break;

            case 3:

                $where[]=['status','=',-1];

                break;

            default:

                $where[]=['status','=',1];

                break;

        }



        $order=['add_time'=>'desc'];

        $field="appointment_id,project_name,project_cover_img,technician_id,day,start_time,end_time,status,reason,cancel_time,operate_type,operate_name";

        $append=['appointment_time_format','cancel_time_small_format'];



        $appointment_model = new AppointmentModel();

        $datas=$appointment_model->with(['technician'=>function($query){

            $query->field('technician_id,name,face,mobile');

        }])->where($where)

            ->order($order)

            ->field($field)

            ->limit($this->request->limit)

            ->page($this->request->page)

            ->select()

            ->append($append)

            ->toArray();

        return $this->success(['datas'=>$datas]);

    }



    public function cancelAppointment()

    {

        $appointment_id=$this->request->param('appointment_id/d',0);

        $reason=$this->request->param('reason');



        if($appointment_id==0) return $this->error('预约不存在');



        if(null == $appointment = AppointmentModel::find($appointment_id)) return $this->error('预约不存在');

        if($appointment->shop_id != $this->request->shopId) return $this->error('预约不存在');

        if(!in_array($appointment->status,[1,4])) return $this->error('预约不存在');

        if($appointment->member_id != $this->request->memberId) return $this->error('预约不存在');



        $appointment->status=-1;

        $appointment->cancel_time=$this->request->time();

        $appointment->reason=$reason;

        $appointment->operate_type=0;

        $appointment->save();

        return $this->success('取消预约成功');

    }



    protected function getTechnicianAppointmentTime($day,$project_id,$technician_id)

    {

        $schedulings=TechnicianSchedulingModel::withCount(['appointment'=>function($query){

            $query->where([

                ['shop_id','=',$this->request->shopId],

                ['status','in',[1,4,8]]

            ]);

        }])->where([

            ['shop_id','=',$this->request->shopId],

            ['technician_id','=',$technician_id],

            ['project_id','=',$project_id],

            ['day','=',$day],

            ['is_delete','=',0],

        ])->field('scheduling_id,start_time,end_time')

            ->select()

            ->toArray();

        foreach ($schedulings  as $k => $v){

            if($day.' '.$v['start_time']<date("Y-m-d H:i",($this->request->time()+(3600*$this->setting->appointment_advance)))){

                $schedulings[$k]['status']=0;

            }else{

                $appointment_num=$v['appointment_num'] ==0 ? $this->setting->appointment_num : $v['appointment_num'];

                if($v['appointment_count'] >= $appointment_num){

                    $schedulings[$k]['status']=0;

                }else{

                    $schedulings[$k]['status']=1;

                }

            }

        }

        return $schedulings;



    }



    public function getAppointmentTime($day)

    {

        $today=date("Y-m-d",$this->request->time());

        $start_time=$this->setting->start_time; $end_time=$this->setting->end_time;

        $appointment_interval=$this->setting->appointment_interval;

        $appointment_advance=$this->setting->appointment_advance;

        $appointment_num=$this->setting->appointment_num;



        $start_time_mintures=$this->ChangeStrToMinutes($start_time);

        $end_time_mintures=$this->ChangeStrToMinutes($end_time);



        $length=(int)ceil(($end_time_mintures-$start_time_mintures)/$appointment_interval);



        $appointment_data=AppointmentModel::where([

            ['shop_id','=',$this->request->shopId],

            ['status','in',[1,4,8]],

            ['day','=',$day],

        ])->field('start_time,end_time')->select()->toArray();



        $datas=[];

        for ($k=0;$k<$length;$k++){

            $datas[$k]['start_time']=$this->ChangeHourMinutestr($start_time_mintures+($appointment_interval)*$k);

            if($k==$length-1){

                $datas[$k]['end_time']=$end_time;

            }else{

                $datas[$k]['end_time']=$this->ChangeHourMinutestr($start_time_mintures+($appointment_interval)*($k+1));

            }



            if($day.' '.$datas[$k]['start_time']<date("Y-m-d H:i",($this->request->time()+(3600*$appointment_advance)))){

                $datas[$k]['status']=0;

            }else{

                $num=0;

                foreach ($appointment_data as $key => $val){

                    if(($val['start_time']>=$datas[$k]['start_time'] && $val['start_time']<$datas[$k]['end_time']) ||

                        ($val['end_time']>$datas[$k]['start_time'] && $val['end_time']<=$datas[$k]['end_time'])){

                        $num++;

                    }

                }



                if($num>=$appointment_num){

                    $datas[$k]['status']=0;

                }else{

                    $datas[$k]['status']=1;

                }

            }

        }



        return $datas;



    }



    public function ChangeStrToMinutes($str)

    {

        $arrminutes = explode(":",$str);

        if (count($arrminutes) == 2) {

            $minutes = $arrminutes[0] * 60 + $arrminutes[1];

            return $minutes;

        } else {

            return 0;

        }

    }



    public function ChangeHourMinutestr($str)

    {

        if ($str !== "0" && $str !== "" && $str !== null) {

            $hour=floor($str/60 ?? 0)<10 ? "0".floor($str/60 ?? 0) :floor($str/60 ?? 0);

            $minutes=($str%60 ?? 0)<10 ? "0".($str%60 ?? 0) : ($str%60 ?? 0) ;



            $hour=$hour ?? '00';

            $minutes=$minutes ?? '00';

            return $hour.":".$minutes;



//            return (strlen((string)floor($str / 60))) < 2 ? "0".(string)floor($str / 60) :

//                (string)floor($str / 60).":".(strlen((string)($str % 60))< 2 ? "0".(string)($str % 60) : (string)($str % 60));

        } else {

            return "";

        }

    }



    protected function getProjectTypeData()

    {

        $where=[

            ['shop_id','=',$this->request->shopId],

            ['is_delete','=',0]

        ];

        $datas=ProjectTypeModel::where($where)

            ->order(['sort'=>'desc'])

            ->field('project_type_id,name')

            ->select()

            ->toArray();

        array_unshift($datas,['project_type_id'=>0,'name'=>'全部']);

        return $datas;

    }



    protected function getProjectData()

    {

        $where=[

            ['shop_id','=',$this->request->shopId],

            ['is_delete','=',0]

        ];

        $datas=ProjectModel::where($where)

            ->order(['take_count'=>'desc','market_price'=>'desc'])

            ->field('project_id,project_type_id,abbreviation,market_price,cover_img')

            ->select()

            ->toArray();



        if(!empty($datas)){

            $projectIds = $engaged_nums  = [];

            foreach($datas as $val){

                $projectIds[$val['project_id']] = $val['project_id'];

            }

            if(!empty($projectIds)){

                $technicianProjectModel = new TechnicianProjectModel();

                $engaged_nums =  $technicianProjectModel->getEngagedNumSumByProjectId($projectIds);

            }

            foreach ($datas as $k => $data){

                $datas[$k]['engaged_num']=$engaged_nums[$data['project_id']] ?? 0;

            }

        }



        return $datas;

    }



    protected function getTechnicianData($technician_ids=[])

    {

        $where=[

            ['shop_id','=',$this->request->shopId],

            ['status','=',1],

            ['is_delete','=',0]

        ];



        if(!empty($technician_ids)){

            $where[]=['technician_id','in',$technician_ids];

        }



        $datas=TechnicianModel::where($where)

            ->order(['add_time'=>'desc'])

            ->field('technician_id,name,face,mobile,position,working_collar')

            ->select()

            ->toArray();



        if(!empty($datas)){

            $technicianIds = $engaged_nums  = [];

            foreach($datas as $val){

                $technicianIds[$val['technician_id']] = $val['technician_id'];

            }

            if(!empty($technicianIds)){

                $technicianProjectModel = new TechnicianProjectModel();

                $engaged_nums =  $technicianProjectModel->getEngagedNumSumByTechnicianId($technicianIds);

            }

            foreach ($datas as $k => $data){

                $datas[$k]['engaged_num']=$engaged_nums[$data['technician_id']] ?? 0;

            }

        }



        return $datas;

    }

}

